package server;

import applet.Client;
import bomberman.DB;
import bomberman.Game;
import bomberman.User;
import bomberman.img.ImageDB;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Hashtable;
import java.util.Map.Entry;
import java.util.Set;
import javax.swing.JOptionPane;

/**
 *
 * @author eirikb
 */
public class BombermanServer extends UnicastRemoteObject implements Server {

    private DB db;
    private Hashtable<String, User> users; // (NICK, USER)
    private Hashtable<String, Client> clients; // (NICK, CLIENT)
    private Hashtable<String, Client> notInGame; // (NICK, CLIENT)
    private Hashtable<String, Game> games; // (GAMENAME, GANE)

    public static void main(String[] args) throws Exception {
        BombermanServer thisServer = new BombermanServer();

        Naming.rebind("BOMBERMAN", thisServer);
        JOptionPane.showMessageDialog(null, "Press OK to terminate the server.");
        Naming.unbind("BOMBERMAN");
        System.out.println("LOL!");
        System.exit(0);
    }

    public BombermanServer() throws RemoteException {

        db = DB.load();
        users = new Hashtable<String, User>();
        clients = new Hashtable<String, Client>();
        games = new Hashtable<String, Game>();
        notInGame = new Hashtable<String, Client>();

        //PING PONG
        new Thread() {

            @Override
            public void run() {
                try {
                    while (true) {
                        Set<Entry<String, Client>> set = clients.entrySet();
                        for (Entry e : set) {
                            Client c = (Client) e.getValue();
                            try {
                                c.pong();
                            } catch (RemoteException r) {
                                r.printStackTrace();
                                removeUser((String) e.getKey());
                            }
                        }

                        Thread.sleep(1000);
                    }
                } catch (Exception e) {
                }

            }
        }.start();
    }

    public void connect() throws RemoteException {

    }

    public ImageDB getImageDB() throws RemoteException {
        return db.getIdb();
    }

    public boolean registerUser(Client client, User user) throws RemoteException {
        for (String nick : users.keySet()) {
            if (nick.equalsIgnoreCase(user.getNick())) {
                return false;
            }
        }
        users.put(user.getNick(), user);
        clients.put(user.getNick(), client);
        notInGame.put(user.getNick(), client);
        client.updateGameList(games);
        for (Client c : clients.values()) {
            c.publicChat(user.getNick() + " joins the game.");
        }
        return true;
    }

    public void disconnect(String nick) throws RemoteException {
        removeUser(nick);
    }

    public void removeUser(String nick) {
        Game g = users.get(nick).getGame();
        if (g != null) {
            try {
                leaveGame(nick);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        users.remove(nick);
        clients.remove(nick);

        notInGame.remove(nick);

        for (Client c : clients.values()) {
            try {
                c.publicChat(nick + " leaves the game.");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void publicChat(String message) throws RemoteException {
        for (Client c : clients.values()) {
            c.publicChat(message);
        }
    }

    public boolean createGame(String nick, Game game) throws RemoteException {
        for (String gName : games.keySet()) {
            if (gName.equalsIgnoreCase(game.getName())) {
                return false;
            }
        }
        User user = users.get(nick);
        user.setGame(game);
        game.addUser(user);
        games.put(game.getName(), game);
        notInGame.remove(nick);
        for (Client c : notInGame.values()) {
            c.addGame(game);
        }
        return true;
    }

    public boolean joinGame(String nick, String gameName) throws RemoteException {
        Game game = games.get(gameName);
        if (game.getUsers().size() < game.getMax()) {
            User user = users.get(nick);
            user.setGame(game);
            game.addUser(user);
            notInGame.remove(nick);
            for (User u : game.getUsers().values()) {
                clients.get(u.getNick()).updateGame(game);
            }
            for (Client c : notInGame.values()) {
                c.addGame(game);
            }
            games.put(game.getName(), game);
            return true;
        }
        return false;
    }

    public void leaveGame(String nick) throws RemoteException {
        User user = users.get(nick);
        Game game = user.getGame();
        game.removeUser(user);
        user.setGame(null);
        if (game.getUsers().size() == 0) {
            games.remove(game.getName());
            for (Client c : notInGame.values()) {
                try {
                    c.removeGame(game);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } else {
            games.put(game.getName(), game);
            for (User u : game.getUsers().values()) {
                clients.get(u.getNick()).updateGame(game);
            }
            for (Client c : notInGame.values()) {
                c.addGame(game);
            }
        }
        notInGame.put(nick, clients.get(nick));
        clients.get(user.getNick()).updateGameList(games);
    }

    public void setReady(String nick, boolean ready) throws RemoteException {
        User user = users.get(nick);
        Game game = user.getGame();
        user.setReady(ready);
        if (game.getUsers().size() > 1 && game.getReady() == game.getUsers().size()) {
            for (User u : game.getUsers().values()) {
                clients.get(u.getNick()).startGame();
            }
            return;
        }
        for (User u : game.getUsers().values()) {
            clients.get(u.getNick()).updateGame(game);
        }

        games.put(game.getName(), game);

    }
    /*            
    public void updateGame(Game game) throws RemoteException {
    games.put(game.getName(), game);
    if (game.getUsers().size() > 1 && game.getReady() == game.getUsers().size()) {
    for (String nick : game.getUsers().keySet()) {
    users.get(nick).startGame();
    }
    return;
    }
    for (String nick : game.getUsers().keySet()) {
    users.get(nick).updateGame(game);
    }
    for (Client c : notInGame.values()) {
    c.addGame(game);
    }
    }
     */
}
